/*
 * DatagramBuilder Library: serialize/deserialize data to/from datagram
 * Copyright (C) 2008 Rakov Ilya <RakovIlya@gmail.com>
 *
 * This library can be distributed under the terms of the GNU LGPLv2.
 * See the file COPYING.LIB.
 */


#ifndef DATAGRAM_CONTAINER_H_
#define DATAGRAM_CONTAINER_H_


/**
 * @file Container.h
 *
 * @brief Container header file
 *
 * @date Dec 3, 2008
 * @author Rakov Ilya
 */


#include "NetHost.h"
#include "CRTPScopedTransaction.h"

#include <boost/assert.hpp>
#include <boost/shared_ptr.hpp>

#include <vector>
#include <limits>
#include <ostream>
#include <stdexcept>
#include <iterator>


using boost::shared_ptr;

/**
 * @brief This exception indicates about serialization troubles.
 */
class serialize_error: public virtual std::runtime_error
{

public:

  /**
   * @brief ctor
   */
  explicit serialize_error( const std::string &arg )
    : std::runtime_error( arg )  {  }

};


/**
 * @brief This exception indicates about deserialization troubles.
 *
 * The deserialize_error will be thrown for reason:
 *  - trying to deserialize too much data
 *  - etc...
 */
class deserialize_error: public virtual std::runtime_error
{

public:

  /**
   * @brief ctor
   */
  explicit deserialize_error( const std::string &arg )
    : std::runtime_error( arg )  {  }

};


/**
 * @brief This class encapsulates container type for data serialization into
 * and data deserialization from.
 *
 * Container widely used by other classes of the framework(such as Builder,
 * Parser, Mark, etc.. ).
 */
class Container
{

public:

  typedef std::vector< char >          container_t;
  typedef container_t::const_pointer   cpointer_t;
  typedef container_t::pointer         pointer_t;
  typedef container_t::const_iterator  citerator_t;
  typedef container_t::iterator        iterator_t;
  typedef container_t::difference_type difference_t;


  /**
   * @brief Provides an ability of safe-exception serialization.
   */
  class ScopedTransaction;


  /**
   * ctor
   * @param isInitialized The flag:
   *  - true - create normal container
   *  - false - create empty stub only(for internal use)
   */
  Container( bool isInitialized = true );


  /**
   * @return Flag whether we have real container or empty stub only
   */
  inline bool IsInitialized() const;


  /**
   * @return Container size
   */
  inline size_t GetSize() const;


  /**
   * @brief Provides an ability to output the EndOfData into an output streams.
   * @param out Output stream
   * @param obj Container
   */
  template< class CharType, class CharTrait >
  friend inline std::basic_ostream< CharType, CharTrait >&
  operator <<( std::basic_ostream<CharType, CharTrait> &out, const Container &obj );


public: /**@{ @name Serialization intarface */

  /**
   * @brief Serializes fixed-size values.
   *
   * The value appends to the end of the already contained data.
   * @param value Value
   */
  template< class T >
  void SerializeValue( const T value );


  /**
   * @brief Serialize variable data from memory range.
   *
   * The value appends to the end of the already contained data.
   *
   * SIZE_T is a data type of the variable data size.
   * @param bgn Pointer to the data begin
   * @param end Pointer to the data end
   * @exception serialization_error
   */
  template< class SIZE_T >
  void SerializeValue( cpointer_t bgn, cpointer_t end );


  /**
   * @brief Serializes fixed-size values.
   *
   * The value serializes by offset.
   * @param value Value.
   * @param offset Position within the container.
   * @exception serialization_error
   */
  template< class T >
  void SerializeValue( const T value, size_t offset );


  /**
   * @brief Deserializes fixed-size values.
   *
   * The value gets by offset.
   * @param value Value
   * @param offset Position within the container.
   * @exception deserialization_error
   */
  template< class T >
  size_t DeSerializeValue( T &value, size_t offset ) const;


  /**
   * @brief Deserializes variable values.
   *
   * The value gets by offset.
   *
   * SIZE_T is a data type of the variable data size.
   * @param inserter Value inserter
   * @param offset Position within the container.
   * @exception deserialization_error
   */
  template< class SIZE_T, class T >
  size_t DeSerializeValue( std::back_insert_iterator<T> inserter, size_t offset ) const;

/**@}*/


private:  // implementation

  void CheckRange( citerator_t bgn, citerator_t end ) const;

  template< class CharType, class CharTrait >
  void ToStream( std::basic_ostream< CharType, CharTrait > &out ) const;


private:  // implementation

  shared_ptr< container_t > container_;

};


#include "impl/ContainerImpl.h"


#endif /* DATAGRAM_CONTAINER_H_ */
